﻿/* Copyright (c) 2001-2009, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
#if !SILVERLIGHT
using System.Data.Common;
#endif
using EffiProz.Core.Errors;
using EffiProz.Core.Rights;
using EffiProz.Core.Lib;

namespace EffiProz.Core.DataTypes
{
    /**
 * Base class for type objects.<p>
 *
 * @author Fred Toussi (fredt@users dot sourceforge.net)
 * @version 1.9.0
 * @since 1.9.0
 */
    public abstract class SqlType : SchemaObject
#if !SILVERLIGHT
        , ICloneable
#endif
    {     
        //
        public int typeComparisonGroup;
        public int typeCode;
        public long precision;
        public int scale;
        public UserTypeModifier userTypeModifier;

        public static SqlType[] emptyArray = new SqlType[0];
        //
        public SqlType(int typeGroup, int type, long precision, int scale)
        {
        
            this.typeComparisonGroup = typeGroup;
            this.typeCode = type;
            this.precision = precision;
            this.scale = scale;
        }

        // interface specific methods
        public virtual int getType()
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            return userTypeModifier.getType();
        }

        public virtual QNameManager.QName getName()
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            return userTypeModifier.getName();
        }

        public virtual QNameManager.QName getCatalogName()
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            return userTypeModifier.getSchemaName().schema;
        }

        public virtual QNameManager.QName getSchemaName()
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            return userTypeModifier.getSchemaName();
        }

        public virtual Grantee getOwner()
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            return userTypeModifier.getOwner();
        }

        public virtual OrderedHashSet getReferences()
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            return userTypeModifier.getReferences();
        }

        public virtual OrderedHashSet getComponents()
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            return userTypeModifier.getComponents();
        }

        public virtual void compile(Session session, SchemaObject parentObject)
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            userTypeModifier.compile(session);
        }

        /**
         *  Retrieves the SQL character sequence required to (re)create the
         *  trigger, as a StringBuffer
         *
         * @return the SQL character sequence required to (re)create the
         *  trigger
         */
        public virtual String getSQL()
        {

            if (userTypeModifier == null)
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }

            return userTypeModifier.getSQL();
        }

        public SqlType duplicate()
        {

            try
            {
                return (SqlType)Clone();
            }
            catch (NotSupportedException )
            {
                throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }
        }

        public abstract int displaySize();

        /**
         * Returns the Ado.Net DbType type number of type, if it exists,
         * otherwise the HSQLDB / SQL type.
         */
        public abstract int getAdoTypeCode();

        /**
         * Returns the CSharp class name of type, if it exists,
         * otherwise the HSQLDB class name.
         */
        public abstract String getCSharpClassName();

        public int? getAdoScale()
        {
            return acceptsScale() ? (int?)scale : null;
        }

        public virtual  int getAdoPrecision()
        {
            return precision > int.MaxValue ? int.MaxValue
                                                 : (int)precision;
        }

        /**
         * Returns the generic SQL CLI type number of type, if it exists,
         * otherwise the HSQLDB type. The generic type is returned for DATETIME
         * and INTERVAL types.
         */
        public virtual int getSQLGenericTypeCode()
        {
            return typeCode;
        }

        /**
         * Returns the name of the type
         */
        public abstract String getNameString();

        /**
         * Returns the name of the type
         */
        public virtual String getFullNameString()
        {
            return getNameString();
        }

        /**
         * Returns the full definition of the type, including parameters
         */
        public abstract String getDefinition();

        public String getTypeDefinition()
        {

            if (userTypeModifier == null)
            {
                return getDefinition();
            }

            return getName().getSchemaQualifiedStatementName();
        }

        public abstract int compare(Session session, Object a, Object b);

        public abstract Object convertToTypeLimits(SessionInterface session,
                Object a);

        /**
         * Explicit casts are handled by this method.
         * SQL standard 6.12 rules for enforcement of size, precision and scale
         * are implemented. For CHARACTER values, it performs truncation in all
         * cases of long strings.
         */
        public virtual Object castToType(SessionInterface session, Object a, SqlType type)
        {
            return convertToType(session, a, type);
        }

        /**
         * Same as castToType except for CHARACTER values. Perform string
         * truncation of trailing spaces only. For other long strings, it raises
         * an exception.
         */
        public abstract Object convertToType(SessionInterface session, Object a,
                                             SqlType type);

        /**
         * Convert type for JDBC. Same as convertToType, but supports non-standard
         * SQL conversions supported by JDBC
         */
        public virtual Object convertToTypeAdo(SessionInterface session, Object a,
                                        SqlType type)
        {
            return convertToType(session, a, type);
        }

        public virtual Object convertCSharpToSQL(SessionInterface session, Object a)
        {
            return a;
        }

        public virtual Object convertSQLToCSharp(SessionInterface session, Object a)
        {
            return a;
        }

        /**
         * Converts the object to the given type. Used for JDBC conversions.
         */
        public abstract Object convertToDefaultType(
            SessionInterface sessionInterface, Object o);

        public abstract String convertToString(Object a);

        public abstract String convertToSQLString(Object a);

        public abstract bool canConvertFrom(SqlType otherType);

        public virtual bool isDistinctType()
        {

            return userTypeModifier == null ? false
                                            : userTypeModifier.schemaObjectType()
                                              == SchemaObjectTypes.TYPE;
        }

        public virtual bool isStructuredType()
        {
            return false;
        }

        public virtual bool isDomainType()
        {

            return userTypeModifier == null ? false
                                            : userTypeModifier.schemaObjectType()
                                              == SchemaObjectTypes.DOMAIN;
        }

        public virtual bool isCharacterType()
        {
            return false;
        }

        public virtual bool isNumberType()
        {
            return false;
        }

        public virtual bool isIntegralType()
        {
            return false;
        }

        public virtual bool isExactNumberType()
        {
            return false;
        }

        public virtual bool isDateTimeType()
        {
            return false;
        }

        public virtual bool isDateTimeTypeWithZone()
        {
            return false;
        }

        public virtual bool isIntervalType()
        {
            return false;
        }

        public virtual bool isBinaryType()
        {
            return false;
        }

        public virtual bool isBooleanType()
        {
            return false;
        }

        public virtual bool isLobType()
        {
            return false;
        }

        public virtual bool isBitType()
        {
            return false;
        }

        public virtual bool isObjectType()
        {
            return false;
        }

        public virtual bool acceptsPrecision()
        {
            return false;
        }

        public virtual bool requiresPrecision()
        {
            return false;
        }

        public virtual long getMaxPrecision()
        {
            return 0;
        }

        public virtual int getMaxScale()
        {
            return 0;
        }

        public virtual int getPrecisionRadix()
        {
            return 0;
        }

        public virtual bool acceptsFractionalPrecision()
        {
            return false;
        }

        public virtual bool acceptsScale()
        {
            return false;
        }

        public virtual int precedenceDegree(SqlType other)
        {

            if (other.typeCode == typeCode)
            {
                return 0;
            }

            return int.MinValue;
        }

        /**
         * Common type used in comparison opertions. other must be comparable
         * with this.
         */
        public abstract SqlType getAggregateType(SqlType other);

        /**
         * Result type of combining values of two types in different opertions.
         * other type is not allways comparable with this, but a operation should
         * be valid without any explicit CAST
         */
        public abstract SqlType getCombinedType(SqlType other, int operation);

        public int compareToTypeRange(Object o)
        {
            return 0;
        }

        /**
         * All arithmetic ops are called on the pre-determined Type object of the result
         */
        public virtual Object absolute(Object a)
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "Type");
        }

        public virtual Object negate(Object a)
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "Type");
        }

        public virtual Object add(Object a, Object b, SqlType otherType)
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "Type");
        }

        public virtual Object subtract(Object a, Object b, SqlType otherType)
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "Type");
        }

        public virtual Object multiply(Object a, Object b)
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "Type");
        }

        public virtual Object divide(Object a, Object b)
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "Type");
        }

        public virtual Object concat(Session session, Object a, Object b)
        {
            throw Error.runtimeError(ErrorCode.U_S0500, "Type");
        }

        public override bool Equals(Object other)
        {

            if (other == this)
            {
                return true;
            }

            if (other is SqlType)
            {
                return ((SqlType)other).typeCode == typeCode
                       && ((SqlType)other).precision == precision
                       && ((SqlType)other).scale == scale
                       && ((SqlType)other).userTypeModifier == userTypeModifier;
            }

            return false;
        }

        public override int GetHashCode()
        {
            return typeCode + (int)precision << 8 + scale << 16;
        }

        ///** @todo 1.9.0 - review all needs max implementation defined lengths, used for parameters */

        // null type
        public static SqlType SQL_ALL_TYPES = NullType.getNullType();

        // character types
        public static CharacterType SQL_CHAR =
            new CharacterType(Types.SQL_CHAR, 1);
        public static CharacterType SQL_CHAR_DEFAULT =
            new CharacterType(Types.SQL_CHAR, CharacterType.defaultCharPrecision);
        public static CharacterType SQL_VARCHAR =
            new CharacterType(Types.SQL_VARCHAR, 0);
        public static CharacterType SQL_VARCHAR_DEFAULT =
            new CharacterType(Types.SQL_VARCHAR,
                              CharacterType.defaultCharPrecision);
        public static ClobType SQL_CLOB = new ClobType();
        public static CharacterType VARCHAR_IGNORECASE =
            new CharacterType(Types.VARCHAR_IGNORECASE, 0);
        public static CharacterType VARCHAR_IGNORECASE_DEFAULT =
            new CharacterType(Types.VARCHAR_IGNORECASE,
                              CharacterType.defaultCharPrecision);

        // binary types
        public static BitType SQL_BIT = new BitType(Types.SQL_BIT, 1);
        public static BitType SQL_BIT_VARYING =
            new BitType(Types.SQL_BIT_VARYING, 1);
        public static BitType SQL_BIT_VARYING_MAX_LENGTH =
            new BitType(Types.SQL_BIT_VARYING, BitType.maxBitPrecision);

        // binary types
        public static BinaryType SQL_BINARY =
            new BinaryType(Types.SQL_BINARY, 1);
        public static BinaryType SQL_BINARY_DEFAULT =
            new BinaryType(Types.SQL_BINARY, 32 * 1024);
        public static BinaryType SQL_VARBINARY =
            new BinaryType(Types.SQL_VARBINARY, 0);
        public static BinaryType SQL_VARBINARY_DEFAULT =
            new BinaryType(Types.SQL_VARBINARY, 32 * 1024);
        public static BlobType SQL_BLOB = new BlobType();

        // other type
        public static OtherType OTHER = OtherType.getOtherType();

        // bool type
        public static BooleanType SQL_BOOLEAN = BooleanType.getBooleanType();

        // number types
        public static NumberType SQL_NUMERIC =
            new NumberType(Types.SQL_NUMERIC, NumberType.defaultNumericPrecision,
                           0);
        public static NumberType SQL_DECIMAL =
            new NumberType(Types.SQL_DECIMAL, NumberType.defaultNumericPrecision,
                           0);
        public static NumberType SQL_DECIMAL_DEFAULT =
            new NumberType(Types.SQL_DECIMAL, NumberType.defaultNumericPrecision,
                           NumberType.defaultNumericScale);
        public static NumberType SQL_DECIMAL_BIGINT_SQR =
            new NumberType(Types.SQL_DECIMAL,
                           NumberType.bigintSquareNumericPrecision, 0);
        public static NumberType SQL_DOUBLE =
            new NumberType(Types.SQL_DOUBLE, 0, 0);

        //
        public static NumberType TINYINT = new NumberType(Types.TINYINT,
            NumberType.tinyintPrecision, 0);
        public static NumberType SQL_SMALLINT =
            new NumberType(Types.SQL_SMALLINT, NumberType.smallintPrecision, 0);
        public static NumberType SQL_INTEGER =
            new NumberType(Types.SQL_INTEGER, NumberType.integerPrecision, 0);
        public static NumberType SQL_BIGINT =
            new NumberType(Types.SQL_BIGINT, NumberType.bigintPrecision, 0);

        // date time
        public static DateTimeType SQL_DATE =
            new DateTimeType(Types.SQL_TIMESTAMP, Types.SQL_DATE, 0);
        public static DateTimeType SQL_TIME =
            new DateTimeType(Types.SQL_TIME, Types.SQL_TIME,
                             DTIType.defaultTimeFractionPrecision);
        public static DateTimeType SQL_TIME_WITH_TIME_ZONE =
            new DateTimeType(Types.SQL_TIME, Types.SQL_TIME_WITH_TIME_ZONE,
                             DTIType.defaultTimeFractionPrecision);
        public static DateTimeType SQL_TIMESTAMP =
            new DateTimeType(Types.SQL_TIMESTAMP, Types.SQL_TIMESTAMP,
                             DTIType.defaultTimestampFractionPrecision);
        public static DateTimeType SQL_TIMESTAMP_WITH_TIME_ZONE =
            new DateTimeType(Types.SQL_TIMESTAMP,
                             Types.SQL_TIMESTAMP_WITH_TIME_ZONE,
                             DTIType.defaultTimestampFractionPrecision);
        public static DateTimeType SQL_TIMESTAMP_NO_FRACTION =
            new DateTimeType(Types.SQL_TIMESTAMP, Types.SQL_TIMESTAMP, 0);

        // interval
        public static IntervalType SQL_INTERVAL_YEAR =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_YEAR,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_MONTH =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_MONTH,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_DAY =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_DAY,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_HOUR =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_HOUR,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_MINUTE =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_MINUTE,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_SECOND =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_SECOND,
                                         DTIType.defaultIntervalPrecision,
                                         DTIType.defaultIntervalFractionPrecision);
        public static IntervalType SQL_INTERVAL_SECOND_MAX_FRACTION =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_SECOND,
                                         DTIType.defaultIntervalPrecision,
                                         DTIType.maxFractionPrecision);
        public static IntervalType SQL_INTERVAL_YEAR_TO_MONTH =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_YEAR_TO_MONTH,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_DAY_TO_HOUR =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_DAY_TO_HOUR,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_DAY_TO_MINUTE =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_DAY_TO_MINUTE,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_DAY_TO_SECOND =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_DAY_TO_SECOND,
                                         DTIType.defaultIntervalPrecision,
                                         DTIType.defaultIntervalFractionPrecision);
        public static IntervalType SQL_INTERVAL_HOUR_TO_MINUTE =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_HOUR_TO_MINUTE,
                                         DTIType.defaultIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_HOUR_TO_SECOND =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_HOUR_TO_SECOND,
                                         DTIType.defaultIntervalPrecision,
                                         DTIType.defaultIntervalFractionPrecision);
        public static IntervalType SQL_INTERVAL_MINUTE_TO_SECOND =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_MINUTE_TO_SECOND,
                                         DTIType.defaultIntervalPrecision,
                                         DTIType.defaultIntervalFractionPrecision);

        //
        public static IntervalType SQL_INTERVAL_YEAR_MAX_PRECISION =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_YEAR,
                                         DTIType.maxIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_MONTH_MAX_PRECISION =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_MONTH,
                                         DTIType.maxIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_DAY_MAX_PRECISION =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_DAY,
                                         DTIType.maxIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_HOUR_MAX_PRECISION =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_HOUR,
                                         DTIType.maxIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_MINUTE_MAX_PRECISION =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_MINUTE,
                                         DTIType.maxIntervalPrecision, 0);
        public static IntervalType SQL_INTERVAL_SECOND_MAX_PRECISION =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_SECOND,
                                         DTIType.maxIntervalPrecision,
                                         DTIType.defaultIntervalFractionPrecision);
        public static IntervalType SQL_INTERVAL_SECOND_MAX_FRACTION_MAX_PRECISION =
            IntervalType.newIntervalType(Types.SQL_INTERVAL_SECOND,
                                         DTIType.maxIntervalPrecision,
                                         DTIType.maxFractionPrecision);

        public static SqlType getDefaultType(int type)
        {

            try
            {
                return getType(type, 0, 0, 0);
            }
            catch (Exception )
            {
                return null;
            }
        }

        public static SqlType getDefaultTypeWithSize(int type)
        {

            switch (type)
            {
                case Types.SQL_ALL_TYPES:
                    return SQL_ALL_TYPES;

                case Types.SQL_CHAR:
                    return SQL_CHAR_DEFAULT;

                case Types.SQL_VARCHAR:
                    return SQL_VARCHAR_DEFAULT;

                case Types.VARCHAR_IGNORECASE:
                    return VARCHAR_IGNORECASE_DEFAULT;

                case Types.SQL_CLOB:
                    return SQL_CLOB;

                case Types.SQL_INTEGER:
                    return SQL_INTEGER;

                case Types.SQL_SMALLINT:
                    return SQL_SMALLINT;

                case Types.SQL_BIGINT:
                    return SQL_BIGINT;

                case Types.TINYINT:
                    return TINYINT;

                case Types.SQL_FLOAT:
                case Types.SQL_REAL:
                case Types.SQL_DOUBLE:
                    return SQL_DOUBLE;

                case Types.SQL_NUMERIC:
                    return SQL_NUMERIC;

                case Types.SQL_DECIMAL:
                    return SQL_DECIMAL;

                case Types.SQL_BOOLEAN:
                    return SQL_BOOLEAN;

                case Types.SQL_BINARY:
                    return SQL_BINARY_DEFAULT;

                case Types.SQL_VARBINARY:
                    return SQL_VARBINARY_DEFAULT;

                case Types.SQL_BLOB:
                    return SQL_BLOB;

                case Types.SQL_BIT:
                    return SQL_BIT;

                case Types.SQL_BIT_VARYING:
                    return SQL_BIT_VARYING;

                case Types.SQL_DATE:
                    return SQL_DATE;

                case Types.SQL_TIME:
                    return SQL_TIME;

                case Types.SQL_TIME_WITH_TIME_ZONE:
                    return SQL_TIME_WITH_TIME_ZONE;

                case Types.SQL_TIMESTAMP:
                    return SQL_TIMESTAMP;

                case Types.SQL_TIMESTAMP_WITH_TIME_ZONE:
                    return SQL_TIMESTAMP_WITH_TIME_ZONE;

                case Types.SQL_INTERVAL_YEAR:
                    return SQL_INTERVAL_YEAR;

                case Types.SQL_INTERVAL_YEAR_TO_MONTH:
                    return SQL_INTERVAL_YEAR_TO_MONTH;

                case Types.SQL_INTERVAL_MONTH:
                    return SQL_INTERVAL_MONTH;

                case Types.SQL_INTERVAL_DAY:
                    return SQL_INTERVAL_DAY;

                case Types.SQL_INTERVAL_DAY_TO_HOUR:
                    return SQL_INTERVAL_DAY_TO_HOUR;

                case Types.SQL_INTERVAL_DAY_TO_MINUTE:
                    return SQL_INTERVAL_DAY_TO_MINUTE;

                case Types.SQL_INTERVAL_DAY_TO_SECOND:
                    return SQL_INTERVAL_DAY_TO_SECOND;

                case Types.SQL_INTERVAL_HOUR:
                    return SQL_INTERVAL_HOUR;

                case Types.SQL_INTERVAL_HOUR_TO_MINUTE:
                    return SQL_INTERVAL_HOUR_TO_MINUTE;

                case Types.SQL_INTERVAL_HOUR_TO_SECOND:
                    return SQL_INTERVAL_HOUR_TO_SECOND;

                case Types.SQL_INTERVAL_MINUTE:
                    return SQL_INTERVAL_MINUTE;

                case Types.SQL_INTERVAL_MINUTE_TO_SECOND:
                    return SQL_INTERVAL_MINUTE_TO_SECOND;

                case Types.SQL_INTERVAL_SECOND:
                    return SQL_INTERVAL_SECOND;

                case Types.OTHER:
                    return OTHER;

                default:
                    return null;
            }            
        }

#if !SILVERLIGHT 
        public static SqlType getEfzType(DbType dbTypeNumber)
        {
            switch (dbTypeNumber)
            {
                case DbType.Int64:
                    return SqlType.SQL_BIGINT;
                case DbType.Int32:
                    return SqlType.SQL_INTEGER;
                case DbType.Int16:
                    return SqlType.SQL_SMALLINT;
                case DbType.Byte:
                    return SqlType.TINYINT;
                case DbType.Single:
                case DbType.Double:
                    return SqlType.SQL_DOUBLE;                
                  
                case DbType.Decimal:
                    return SqlType.SQL_DECIMAL_DEFAULT;

                case DbType.String:
                case DbType.AnsiString:
                    return SqlType.SQL_VARCHAR;
                case DbType.AnsiStringFixedLength:
                case DbType.StringFixedLength:
                    return SqlType.SQL_CHAR;

                case DbType.Boolean:
                    return SqlType.SQL_BOOLEAN;

                case DbType.Date:
                    return SqlType.SQL_DATE;
                case DbType.Time:
                    return SqlType.SQL_TIME;
                case DbType.DateTime:
                case DbType.DateTime2:
                    return SqlType.SQL_TIMESTAMP;

                case DbType.Binary:
                    return SqlType.SQL_VARBINARY;

                case DbType.Object:
                    return SqlType.OTHER;    

                default:
                    throw new NotSupportedException(String.Format("DbType :{0}", dbTypeNumber));    
            }
        }
#endif
        /**
         * translate an public type number to JDBC type number if a type is not
         * supported internally, it is returned without translation
         *
         * @param type int
         * @return int
         */
        public static int getJDBCTypeCode(int type)
        {

            switch (type)
            {

                case Types.SQL_BLOB:
                    return Types.BLOB;

                case Types.SQL_CLOB:
                    return Types.CLOB;

                case Types.SQL_BIGINT:
                    return Types.BIGINT;

                case Types.SQL_BINARY:
                    return Types.BINARY;

                case Types.SQL_VARBINARY:
                    return Types.VARBINARY;

                case Types.SQL_BIT:
                case Types.SQL_BIT_VARYING:
                    return Types.BIT;

                default:
                    return type;
            }
        }

        /**
         * Enforces precision and scale limits on type
         */
        public static SqlType getType(int type, int collation, long precision,
                                   int scale)
        {
    
            switch (type)
            {

                case Types.SQL_ALL_TYPES:
                    return SQL_ALL_TYPES;

                //                return SQL_ALL_TYPES; // needs changes to Expression type resolution
                case Types.SQL_CHAR:
                case Types.SQL_VARCHAR:
                case Types.VARCHAR_IGNORECASE:
                case Types.SQL_CLOB:
                    return CharacterType.getCharacterType(type, precision);

                case Types.SQL_INTEGER:
                    return SQL_INTEGER;

                case Types.SQL_SMALLINT:
                    return SQL_SMALLINT;

                case Types.SQL_BIGINT:
                    return SQL_BIGINT;

                case Types.TINYINT:
                    return TINYINT;

                case Types.SQL_FLOAT:
                    if (precision > 53)
                    {
                        throw Error.error(ErrorCode.X_42592, "" + precision);
                    }
                    goto case Types.SQL_REAL;
                // fall through
                case Types.SQL_REAL:
                case Types.SQL_DOUBLE:
                    return SQL_DOUBLE;

                case Types.SQL_NUMERIC:
                case Types.SQL_DECIMAL:
                    if (precision == 0)
                    {
                        precision = NumberType.defaultNumericPrecision;
                    }

                    return NumberType.getNumberType(type, precision, scale);

                case Types.SQL_BOOLEAN:
                    return SQL_BOOLEAN;

                case Types.SQL_BINARY:
                case Types.SQL_VARBINARY:
                case Types.SQL_BLOB:
                    return BinaryType.getBinaryType(type, precision);

                case Types.SQL_BIT:
                case Types.SQL_BIT_VARYING:
                    return BitType.getBitType(type, precision);

                case Types.SQL_DATE:
                case Types.SQL_TIME:
                case Types.SQL_TIME_WITH_TIME_ZONE:
                case Types.SQL_TIMESTAMP:
                case Types.SQL_TIMESTAMP_WITH_TIME_ZONE:
                    return DateTimeType.getDateTimeType(type, scale);

                case Types.SQL_INTERVAL_YEAR:
                case Types.SQL_INTERVAL_YEAR_TO_MONTH:
                case Types.SQL_INTERVAL_MONTH:
                case Types.SQL_INTERVAL_DAY:
                case Types.SQL_INTERVAL_DAY_TO_HOUR:
                case Types.SQL_INTERVAL_DAY_TO_MINUTE:
                case Types.SQL_INTERVAL_DAY_TO_SECOND:
                case Types.SQL_INTERVAL_HOUR:
                case Types.SQL_INTERVAL_HOUR_TO_MINUTE:
                case Types.SQL_INTERVAL_HOUR_TO_SECOND:
                case Types.SQL_INTERVAL_MINUTE:
                case Types.SQL_INTERVAL_MINUTE_TO_SECOND:
                case Types.SQL_INTERVAL_SECOND:
                    return IntervalType.getIntervalType(type, precision, scale);

                case Types.OTHER:
                    return OTHER;

                default:
                    throw Error.runtimeError(ErrorCode.U_S0500, "Type");
            }
        }

        public static SqlType getAggregateType(SqlType add, SqlType existing)
        {
            if (add == null && existing == null)
                return SqlType.SQL_ALL_TYPES;

            if (existing == null || existing.typeCode == Types.SQL_ALL_TYPES)
            {
                return add;
            }

            if (add == null || add.typeCode == Types.SQL_ALL_TYPES)
            {
                return existing;
            }

            return existing.getAggregateType(add);
        }

        public static Dictionary<string, int> typeAliases;
        public static Dictionary<string, int> typeNames;

        static SqlType()
        {
            typeNames = new Dictionary<string, int>(37);

            typeNames.Add("CHARACTER", Types.SQL_CHAR);
            typeNames.Add("VARCHAR", Types.SQL_VARCHAR);
            typeNames.Add("VARCHAR_IGNORECASE", Types.VARCHAR_IGNORECASE);
            typeNames.Add("DATE", Types.SQL_DATE);
            typeNames.Add("TIME", Types.SQL_TIME);
            typeNames.Add("TIMESTAMP", Types.SQL_TIMESTAMP);
            typeNames.Add("INTERVAL", Types.SQL_INTERVAL);
            typeNames.Add("TINYINT", Types.TINYINT);
            typeNames.Add("SMALLINT", Types.SQL_SMALLINT);
            typeNames.Add("INTEGER", Types.SQL_INTEGER);
            typeNames.Add("BIGINT", Types.SQL_BIGINT);
            typeNames.Add("REAL", Types.SQL_REAL);
            typeNames.Add("FLOAT", Types.SQL_FLOAT);
            typeNames.Add("DOUBLE", Types.SQL_DOUBLE);
            typeNames.Add("NUMERIC", Types.SQL_NUMERIC);
            typeNames.Add("DECIMAL", Types.SQL_DECIMAL);
            typeNames.Add("BOOLEAN", Types.SQL_BOOLEAN);
            typeNames.Add("BINARY", Types.SQL_BINARY);
            typeNames.Add("VARBINARY", Types.SQL_VARBINARY);
            typeNames.Add("CLOB", Types.SQL_CLOB);
            typeNames.Add("BLOB", Types.SQL_BLOB);
            typeNames.Add("BIT", Types.SQL_BIT);
            typeNames.Add("OTHER", Types.OTHER);

            //
            typeAliases = new Dictionary<string, int>(64);

            typeAliases.Add("CHAR", Types.SQL_CHAR);
            typeAliases.Add("INT", Types.SQL_INTEGER);
            typeAliases.Add("DEC", Types.SQL_DECIMAL);
            typeAliases.Add("LONGVARCHAR", Types.LONGVARCHAR);
            typeAliases.Add("DATETIME", Types.SQL_TIMESTAMP);
            typeAliases.Add("LONGVARBINARY", Types.LONGVARBINARY);
            typeAliases.Add("OBJECT", Types.OTHER);
        }

        public static int getTypeNr(String name)
        {

            int i;

            if (!typeNames.TryGetValue(name, out i))
            {
                if (!typeAliases.TryGetValue(name, out i))
                    i = int.MinValue;
            }

            return i;
        }

        public static bool isSupportedSQLType(int typeNumber)
        {

            if (getDefaultType(typeNumber) == null)
            {
                return false;
            }

            return true;
        }

        public static bool matches(SqlType[] one, SqlType[] other)
        {

            for (int i = 0; i < one.Length; i++)
            {
                if (one[i].typeCode != other[i].typeCode)
                {
                    return false;
                }
            }

            return true;
        }

        public Object Clone()
        {
            throw new NotImplementedException();
        }

    }
}
